﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Security.Cryptography;
using DotNetUtilityLibrary;
using System.Threading;

namespace CryptographyDemonstration
{
	public partial class MainForm : Form
	{

		#region Fields

		private RSACryptoServiceProvider mProvider;
		private int mKeySize;

		private List<GenericWrapper<int>> mPossibleKeySizes =
			new List<GenericWrapper<int>>()
		{
			new GenericWrapper<int>(512),
			new GenericWrapper<int>(1024),
			new GenericWrapper<int>(2048),
			new GenericWrapper<int>(4096)
		};

		#endregion Fields

		#region Constructor

		public MainForm()
		{
			InitializeComponent();
			cbKeyLength.DataSource = mPossibleKeySizes;
			cbKeyLength.DisplayMember = "DisplayName";
		}

		#endregion Constructor

		#region Event Handlers

		private void btnGenerateKeyPair_Click(object sender, EventArgs e)
		{
			GenerateNewKeyPair();
		}

		private void cbKeyLength_SelectedIndexChanged(object sender, EventArgs e)
		{
			mKeySize = ((GenericWrapper<int>)cbKeyLength.SelectedItem).Item;
			GenerateNewKeyPair();
		}

		private void btnDecrypt_Click(object sender, EventArgs e)
		{
			Decrypt();
		}

		#endregion Event Handlers

		#region Private Methods

		private void GenerateNewKeyPair()
		{
			ToggleUI(false);
			BackgroundWorkerHelper.RunAsyncWork(new DoWorkEventHandler(
				(object sender, DoWorkEventArgs e) =>
				{
					StallForKeyGeneration();
					if (mProvider != null)
						mProvider.Dispose();
					mProvider = new RSACryptoServiceProvider(mKeySize);
					mProvider.PersistKeyInCsp = false;
					UpdateKeyInformation();
					Decrypt();
				}),
				new RunWorkerCompletedEventHandler(
				(object sender, RunWorkerCompletedEventArgs e) =>
				{
					ToggleUI(true);
				}));
		}

		private void UpdateKeyInformation()
		{
			if (this.InvokeRequired)
			{
				this.Invoke(new MethodInvoker(() => UpdateKeyInformation()));
				return;
			}

			txtPublicKeyInformation.Text =
				XMLHelper.FormatXml(mProvider.ToXmlString(false));
			txtPrivateKeyInformation.Text =
				XMLHelper.FormatXml(mProvider.ToXmlString(true));
		}

		private void StallForKeyGeneration()
		{
			if (this.InvokeRequired)
			{
				this.Invoke(new MethodInvoker(() => StallForKeyGeneration()));
				return;
			}

			txtPublicKeyInformation.Text =
				"Generating a new key pair...";
			txtPrivateKeyInformation.Text =
				"Generating a new key pair...";
			this.Update();
		}

		private void ToggleUI(bool toggle)
		{
			if (this.InvokeRequired)
			{
				this.Invoke(new MethodInvoker(() => ToggleUI(toggle)));
				return;
			}
			
			cbKeyLength.Enabled = toggle;
			txtEncryptedText.Enabled = toggle;
			btnGenerateKeyPair.Enabled = toggle;
			btnDecrypt.Enabled = toggle;
			if (toggle)
			{
				txtEncryptedText.BackColor = SystemColors.Window;
			}
			else
			{
				txtEncryptedText.BackColor = SystemColors.ControlLight;
			}
		}

		public void UpdatePlainText(string encryptedText)
		{
			if (this.InvokeRequired)
			{
				this.Invoke(new MethodInvoker(() => UpdatePlainText(encryptedText)));
				return;
			}
			txtPlainText.Text = encryptedText;
		}

		private void Decrypt()
		{
			// Wrap up a change the CryptographyHelper with ConvertHelper calls to
			// transparently change the displaying functionality
			UpdatePlainText(
					CryptographyHelper.AsymmetricDecrypt(mProvider,
						ConvertHelper.BytesToString(
							ConvertHelper.HexStringToBytes(txtEncryptedText.Text)
						)
					)
				);
		}

		#endregion Private Methods

	}
}
